package de.tum.wi.som.prio.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import de.tum.wi.som.Node;
import de.tum.wi.som.Project;
import de.tum.wi.som.prio.PriorityRule;
import de.tum.wi.som.util.PrioUtil;

/**
 * Minimum late finish time
 * 
 * Min(LF_il)
 * 
 * <pre>
 * LF_il = latest finish time
 * </pre>
 * 
 * @author Goetz Epperlein
 */
public class MinimumLateFinishTime implements PriorityRule {

	@Override
	public void prioritize(Project project) {

		ArrayList<Node> remainingNodes = new ArrayList<Node>();
		ArrayList<Node> scheduledNodes = new ArrayList<Node>();
		List<Node> accessibleNodes;

		// calc latest finish time
		project.calcProjectGraph();
		remainingNodes.addAll(Arrays.asList(project.getNodes()));
		Node source = project.getSource();
		
		Node dummyNode = new Node(0, new int[0]);
		Node candidateNode;

		// iterate over all nodes still not in sorted
		while (!remainingNodes.isEmpty()) {
			accessibleNodes = PrioUtil.determineAccesibleNodes(scheduledNodes, source, remainingNodes);
            if (accessibleNodes.size() == 0) {
            	System.err.println("No accessible nodes found in MinimumLateFinishTime");
            	return;
            }
			
            candidateNode = dummyNode;
			Double latestFinishTimeRun = 0.0;
			Double latestFinishTimeIs = 0.0;

			// search for smallest latest finish time
			for (Node n : accessibleNodes) {

				latestFinishTimeRun = n.getLatestFinish();

				if (candidateNode == dummyNode || latestFinishTimeIs <= 0.0 || latestFinishTimeRun < latestFinishTimeIs) {
					latestFinishTimeIs = latestFinishTimeRun;
					candidateNode = n;
				}
			}

			// add node with smallest to schedule
			remainingNodes.remove(candidateNode);
			scheduledNodes.add(candidateNode);
		}
		project.setNodes(scheduledNodes.toArray(new Node[scheduledNodes.size()]));
	}
	
	@Override
	public String toString(){
		return "MinimumLateFinishTime";
	}
}
